-module(server_logic).

%% API
-export([start/0, dispose/0, run_tests/2, show_tests/1, prepare_tests_auto/0]).
-include("definitions.hrl").

-spec start/0 :: () -> 'ok' | {'error', Reason} when Reason :: term().
start() ->
  global:register_name(server_logic, self()),
  start_listeners(),
  storage_supervisor:start(),
  Devices = device_manager:get_device_list(),
  add_test_if_debug(),
  TestIds = storage:get_all_test_ids(),
  {WxFrame, Grid} = server_ui:create_window(Devices, TestIds),
  true = test_executor_supervisor:init(Devices),
  server_ui:event_loop(WxFrame, Grid, Devices).

start_listeners() ->
  {ok, InfoNode} = application:get_env(info_node),
  {ok, MainNode} = application:get_env(main_node),
  pong = net_adm:ping(InfoNode),
  pong = net_adm:ping(MainNode),

  P1 = my_ping:start(MainNode, main_node_listener, server_logic, [info_node_listener]),
  P2 = my_ping:start(InfoNode, info_node_listener, server_logic, [main_node_listener]),
  erlang:monitor(process, P1),
  erlang:monitor(process, P2),
  receive
    {started, main_node_listener} ->
      io:format("~p {~p} started~n", [main_node_listener, P1])
  after 5000 -> error(main_node_listener_dint_answer)
  end,
  receive
    {started, info_node_listener} ->
      io:format("~p {~p}  started~n", [info_node_listener, P2])
  after 5000 -> error(info_node_listener_dint_answer)
  end,

  global:whereis_name(main_node_listener) ! start_loop,
  global:whereis_name(info_node_listener) ! start_loop
.

-spec show_tests/1 :: (integer()) -> yes.
show_tests(DeviceCount) ->
  {ok, Node} = application:get_env(info_node),
  pong = net_adm:ping(Node),
  info_ui:start(DeviceCount, Node).
%%   spawn(info_ui, start, [self(), DeviceCount]).


-spec prepare_tests_auto/0 :: () -> {[device()], dict:dict(device_id(), test_id())}.
prepare_tests_auto() ->
  {ok, Count} = application:get_env(devices_limit),
  Numbers = lists:seq(1, Count),
  DevList = device_manager:get_device_list(Numbers, []),

  TestsIds = storage:get_all_test_ids(),
  TestsDict = case TestsIds of
                [] -> error("no tests in db");
                [H | _] -> gen_dict_tests(DevList, H, dict:new())
              end,
  {DevList, TestsDict}
.

%% deviceId -> testId
-spec gen_dict_tests/3 :: (Devices, Tests, Acc) -> Res
  when
  Devices :: [device()],
  Tests :: test_id(),
  Acc :: dict:dict(device_id(), test_id()),
  Res :: dict:dict(device_id(), test_id()).

gen_dict_tests([], _, Acc) -> Acc;

gen_dict_tests([#deviceDescriptor{id = N} | Tail], Test, Acc) ->
  NewAcc = dict:store(N, Test, Acc),
  gen_dict_tests(Tail, Test, NewAcc).


-spec run_tests/2 :: ([device()], dict:dict()) -> {ok, testsRunning}.
run_tests(Devices, Tests) ->
  {ok, testsRunning} = test_executor_supervisor:start(Devices, Tests).

-spec dispose/0 :: () -> ok | {error, Reason} when Reason :: term().
dispose() ->
  stop_node_listeners(),
  ok = test_executor_supervisor:stop(),
  ok = info_ui:stop(),
  ok = storage_supervisor:stop(),
  wx:destroy(),
  application:stop(ssu2015DeviceTest).

stop_node_listeners() ->
  M1 = my_ping:stop(main_node_listener),
  M2 = my_ping:stop(info_node_listener),
  io:format("main: ~p.  info: ~p ~n", [M1, M2]).


%для первых тестов
-spec add_test_if_debug/0 :: () -> ok.
add_test_if_debug() ->
  {ok, IsDebug} = application:get_env(debug),
  case IsDebug of
    true ->
      ok = storage_supervisor:insert_samples();
    false -> ok
  end.